Property based testing
参考
ただただランダムに値を生成するのではなく、問題が起きそうな値もやや恣意的に含む
単純で自明な実装と結果を比較する
実装本体はいくらでも最適化すれば良い
例えば、max :: [Int] -> Intのような関数を定義する際に、
自明な実装の方はmax' = last . sortのように定義する
これで、ランダムに生成し、maxとmax'の結果が一致することを確認する
関数の等価性を使ってチェックするのかmrsekut.icon code:ts
// Properties
test("biggest", () => {
fc.assert(
fc.property(fc.array(fc.float(), { minLength: 1 }), (n) => {
return biggest(n) === modelBiggest(n);
})
);
});
const biggest = (numbers: number[]) => {
return numbers.reduce((acc, curr) => (acc > curr ? acc : curr), -Infinity);
};
// helper
const modelBiggest = (numbers: number[]) => {
};
構成要素同士の不変条件を確認する
sortで、
隣り合う2つの要素を比べたときに常に後者が大きくなる
実行の前後で要素数が一致する
など
いくつかの不変条件を組み合わせないと変な実装でも常にpassしてしまう可能性があることに注意する
2つの関数が逆方向に動作する場合、それらを組み合わせて同じ結果になることを確認する
2つである必要もなく、複数の関数が円環に動作するなら使える
e.g.
encode/decode
code:ts
describe("properties", () => {
test("synmetry", () => {
fc.assert(
fc.property(fc.string(), (text) => {
return decode(encode(text)) === text;
})
);
});
});
const encode = (text: string) => text.split("").join(",");
const decode = (encoded: string) => encoded.split(",").join("");
ちなみに上記コードは","という入力を与えたときに失敗する